#include "user_main.h"

static const char *TAG = "global";


static int data_update_flag = 0;
static float g_battery_vol = 0;
static float g_temp = 0;

static const char *temperature_sensor_config_topic="homeassistant/sensor/ODP1T/config";
static const char *temperature_sensor_config_payload="{\"device_class\":\"temperature\",\"name\":\"ODP1Temperature\",\"unique_id\":\"ODP1Temperature\",\"state_topic\":\"homeassistant/sensor/ODP1/state\",\"unit_of_measurement\":\"C\",\"value_template\":\"{{ value_json.temperature}}\"}";

static const char *voltage_sensor_config_topic="homeassistant/sensor/ODP1B/config";
static const char *voltage_sensor_config_payload="{\"device_class\":\"voltage\",\"name\":\"ODP1Battery\",\"unique_id\":\"ODP1Battery\",\"state_topic\":\"homeassistant/sensor/ODP1/state\",\"unit_of_measurement\":\"V\",\"value_template\":\"{{ value_json.voltage}}\"}";

static const char *update_data_topic = "homeassistant/sensor/ODP1/state";

#if SUPPORT_FIRMWARE_OTA
static const char *ota_version_url = "http://norep.gitee.io/ota/ota_test/version";
static const char *ota_image_url = "http://norep.gitee.io/ota/ota_test/ota.bin";
#endif

static int user_get_cb(httpd_req_t *req)
{
    httpd_resp_send(req, index_html_start, index_html_end - index_html_start);
    return 0;
}

static int user_post_cb(httpd_req_t *req, char *content, int len)
{
    system_status_t *sys_sta = get_sys_sta();
    char ssid[32];
    char passwd[32];
    int ret = httpd_query_key_value(content,"ssid",ssid,sizeof(ssid));
    if(ret == ESP_OK) {
        printf("ssid = %s\n",ssid);
    }
    else {
        printf("error = %d\n",ret);
    }

    ret = httpd_query_key_value(content,"password",passwd,sizeof(passwd));
    if(ret == ESP_OK) {
        printf("password = %s\n",passwd);
    }
    else {
        printf("error = %d\n",ret);
    }

    if (strlen(ssid) && strlen(passwd)) {
        my_nvs_wifi_info_set(ssid, passwd);
    }
    httpd_resp_send(req, save_html_start, save_html_end - save_html_start);
    sys_sta->reboot_flag = 1;
    return 0;
}

static void WIFI_Connect_cb(char *ip)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 1;
    ESP_LOGW(TAG, "wifi connect : %s", ip);
}

static void WIFI_Disconnect_cb(void)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 0;
    ESP_LOGW(TAG, "wifi disconnect");
}

static void WIFI_AP_STAConnect_cb(void)
{
    ESP_LOGW(TAG, "WIFI_AP_STAConnect_cb");

    my_http_cb_t user_cb;
    user_cb.get_cb = user_get_cb;
    user_cb.post_cb = user_post_cb;
    my_http_server_set_callback(user_cb);
    ESP_LOGW(TAG, "Starting webserver");
    my_start_webserver();

}

static void WIFI_AP_STADisconnect_cb(void)
{
    ESP_LOGW(TAG, "WIFI_AP_STADisconnect_cb");
}

static void Networl_init(void)
{
    my_wifi_t wifi_info = {};
    wifi_mode_t wifi_init_mode = WIFI_MODE_AP;

    // if (my_nvs_wifi_info_get(&wifi_info)) {

    // 	memset(&wifi_info, 0, sizeof(wifi_info));
    // 	memcpy(wifi_info.ssid, DEFAULT_AP_MODE_SSID, strlen(DEFAULT_AP_MODE_SSID));

    // 	if (strlen(DEFAULT_AP_MODE_PASSWORD) > 0) {
    // 		memmove(wifi_info.password, DEFAULT_AP_MODE_PASSWORD, strlen(DEFAULT_AP_MODE_PASSWORD));
    // 	}

    // 	wifi_info.max_connection = 1;

    // 	wifi_info.ap_staconnect_cb = WIFI_AP_STAConnect_cb;
    // 	wifi_info.ap_stadisconnect_cb = WIFI_AP_STADisconnect_cb;

    // 	wifi_init_mode = WIFI_MODE_AP;
    // } else
     {
        sprintf((char*)wifi_info.ssid, "HONOR-0415PD");
        sprintf((char*)wifi_info.password, "pf0105602");

        wifi_info.connect_cb = WIFI_Connect_cb;
        wifi_info.disconnect_cb = WIFI_Disconnect_cb;

        wifi_init_mode = WIFI_MODE_STA;
    }
    my_wifi_init(&wifi_info, wifi_init_mode);
}

/**
 * @brief 获取adc对应的电压
 * @param adc_cur : adc采集的当前值
 * @param adc_scale : 外部adc电阻分压倍率
 * @return ：计算出的电压
 * */
static float Get_voltage(uint16_t adc_cur, float adc_scale)
{
    double voltage = 0;

    // voltage = (adc_cur / 1023.0) * adc_scale;
    voltage = (adc_cur - 12) / 198.0;
    return (float)voltage;
}

// Depend on menuconfig->Component config->PHY->vdd33_const value
// When measuring system voltage(ADC_READ_VDD_MODE), vdd33_const must be set to 255.
static void user_adc_init(void)
{
    adc_config_t adc_config;
    adc_config.mode = ADC_READ_TOUT_MODE;
    adc_config.clk_div = 8; // ADC sample collection clock = 80MHz/clk_div = 10MHz
    ESP_ERROR_CHECK(adc_init(&adc_config));
}

static int sys_callback(void)
{
    int ret = 0;
    static int count = 0;
    uint16_t adc_val = 0;
    count++;
    if (count >= 10) {
        count = 0;
        adc_read(&adc_val);
        g_battery_vol = Get_voltage(adc_val, 5.7);

        ret = DS18B20_Read_Temperature(&g_temp);
        if (ret <= -1) {
            printf("DS18B20_Read_Temperature Error ret:%d\n", ret);
        } else {
            // printf("DS18B20 temp: %.2f\n", g_temp);
        }
        data_update_flag = 1;
        // printf("adc read: %d, voltage:%.2f\n", adc_val, g_battery_vol);
    }

    return 0;
}

/* DS18B20控制IO操作函数 */
static void DS18B20_out_cb(int sta)
{
    gpio_set_level(DS18B20_GPIO, sta);
}

static int DS18B20_in_cb(void)
{
    return gpio_get_level(DS18B20_GPIO);
}

/* DS18B20控制IO模式配置 */
static void DS18B20_OutPut_Mode_cb(void)
{
    gpio_set_direction(DS18B20_GPIO, GPIO_MODE_OUTPUT);
}

static void DS18B20_InPut_Mode_cb(void)
{
    gpio_set_direction(DS18B20_GPIO, GPIO_MODE_INPUT);
}

/* DS18B20 us 级延时函数 */
static void DS18B20_delay_us_cb(uint32_t us)
{
    ets_delay_us((uint16_t)us);
}

static int Init_DS18B20(void)
{
    gpio_config_t IO_config;
    IO_config.pin_bit_mask = GPIO_DS18B20_MASK;
    IO_config.mode = GPIO_MODE_OUTPUT;
    IO_config.pull_up_en = GPIO_PULLUP_ENABLE;
    IO_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    IO_config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&IO_config);

    DS18B20_init_t init_cb;
    init_cb.delay_us_cb = DS18B20_delay_us_cb;
    init_cb.in_cb = DS18B20_in_cb;
    init_cb.out_cb = DS18B20_out_cb;
    init_cb.in_mode_cb = DS18B20_InPut_Mode_cb;
    init_cb.out_mode_cb = DS18B20_OutPut_Mode_cb;
    
    return DS18B20_Init(init_cb);
}

static void MY_MQTT_Connect_cb(void)
{
    printf("MQTT Connect SUCCESS\n");
    my_mqtt_publish(temperature_sensor_config_topic, temperature_sensor_config_payload, 0, 1, 1);
    my_mqtt_publish(voltage_sensor_config_topic, voltage_sensor_config_payload, 0, 1, 1);
}

static void MY_MQTT_DISConnect_cb(void)
{
}

static void MY_MQTT_RecData_cb(char *topic, int topic_len, char *data, int data_len)
{
}

static void init_my_mqtt()
{
    my_mqtt_init_info_t mqtt_init_cfg = {0};

    mqtt_init_cfg.host = "pi.oynote.top";
    mqtt_init_cfg.port = 1883;
    mqtt_init_cfg.connect_cb = MY_MQTT_Connect_cb;
    mqtt_init_cfg.disconnect_cb = MY_MQTT_DISConnect_cb;
    mqtt_init_cfg.received_cb = MY_MQTT_RecData_cb;

    my_mqtt_init(mqtt_init_cfg);
}

static void mqtt_task(void *arg)
{
    system_status_t *sys_sta = get_sys_sta();
    while (sys_sta->network_sta != 1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    init_my_mqtt();

    char buf[256];

    while (1)
    {
        while (sys_sta->network_sta)
        {
            if (data_update_flag) {

                // printf("DS18B20 temp: %.2f\n", g_temp);
                // printf("adc voltage:%.2f\n", g_battery_vol);

                memset(buf, 0, sizeof(buf));
                snprintf(buf, sizeof(buf), "{\"temperature\":%.2f,\"voltage\":%.2f}", g_temp, g_battery_vol);

                // printf("buf:%s\n", buf);
                my_mqtt_publish(update_data_topic, buf, 0, 0, 1);

                data_update_flag = 0;
            }
            vTaskDelay(4000 / portTICK_PERIOD_MS);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void app_main()
{
    int ret = 0;

    system_status_t *sys_sta = get_sys_sta();
    const esp_app_desc_t *app_desc = esp_ota_get_app_description();
    sys_sta->version = (char *)app_desc->version;
    ESP_LOGI(TAG, "app_version:%s", sys_sta->version); 

#if SUPPORT_FIRMWARE_OTA
    sys_sta->ota_version_path = ota_version_url;
    sys_sta->ota_image_path = ota_image_url;
#endif
    sys_sta->sys_cb = sys_callback;

    user_adc_init();

    ret = Init_DS18B20();
    if (ret) {
        printf("DS18B20 init error\n");
    }

    DS18B20_Resolution_Config(DS18B20_12BIT);

    system_init();

    ESP_LOGI(TAG, "start connect wifi...");
    Networl_init();
    ESP_LOGI(TAG, "Run");

    esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
    esp_pm_config_esp8266_t pm_config = {
            .light_sleep_enable = true
    };
    ESP_ERROR_CHECK(esp_pm_configure(&pm_config));

    ESP_LOGI(TAG,"create update mqtt task");
    new_task(mqtt_task, "mqtt_task", 1024 * 4, NULL, 25);

    printf("\n");
    printf("free_heap_size: %d KB\n", esp_get_free_heap_size() / 1024);
    printf("minimum_free_heap_size: %d KB\n", esp_get_minimum_free_heap_size() / 1024);
    printf("\n");

}
